/** @file filehandler.h
	@brief A simple file and directory handler */

#ifndef G3_FILE_HANDLER_H
#define G3_FILE_HANDLER_H

#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>

#include "singleton.h"
#include "text.h"

#include "f_zipper.h"
#include "f_cistream.h"

/** Windows and unix have different slashes */
#ifdef WIN32
	#define G3_SLASH	"\\"
#else
	#define G3_SLASH	"/"
#endif

namespace G3 {

/** @class PATH_DIR
	@brief Either a real filepath or a filepath into a compressed file*/
class PATH_DIR {
	public:
        /**
            @brief Constructor that sets zipped to false
        */
		PATH_DIR ();

        /** Does this path lead to a compressed file ? */
		bool zipped;
        /** Compressed directory handler */
		ZIPPER zip;

        /** The path string */
		std::string path;
};

/** @class FILEHANDLER
	@brief Filehandler
	\todo Fix the lastBuffer hax*/
class FILEHANDLER: public SINGLETON <FILEHANDLER> {
    public:
        /**
            Constructor that NULLs the pointers
        */
		FILEHANDLER ();

        /** Pointer to the log */
		G3::LOG *log;

        /**
            @brief Makes a directory
            @param[in] dir Reference to the directory to be created.
            Note that creating directories inside compressed folders
            is not supported yet.
            @return True on success, false on failure
        */
		bool MkDir (const std::string &dir);

        /**
            @brief Erases a file
            @param[in] file Reference to the path of the file to be erased.
            Note that erasing files inside compressed folders
            is not supported yet.
            @return True on success, false on failure
        */
		bool EraseFile (const std::string &file);

        /**
            @brief Reads a file
            @param[in] filename Reference to the path of the file to be read
            @param[in] data Pointer to a byte buffer (if it already exists)
            @param[out] size Pointer to the number of bytes read
            @return Pointer to the read bytes or NULL on failure
        */
        byte *Read (const std::string &filename, byte *data, ulong *size);

        /**
            @brief Buffers a whole file into a circular stream
            @param[in] filename Reference to the path of the file to be buffered
            @return Pointer to the brand new circular stream
        */
		CISTREAM *ReadWholeFile (const std::string &filename);

        /**
            @brief Writes a whole stream into a file
            @param[in] filename Reference to the path of the file to be written
            @param[in] Stream Pointer to the stream to be written into the file
            @return True on success, false on failure
        */
		bool WriteWholeStream (const std::string &filename, STREAM *Stream);

        /**
            @brief Writes into a file
            @param[in] filename Reference to the path of the file to be written
            @param[in] data Pointer to the data to be written
            @param[in] size Number of bytes to write into the file
            @return True on success, false on failure
        */
        bool Write (const std::string &filename, byte *data, ulong size);

        /**
            @brief Checks if the file exists
            @param[in] filename Reference to the path of the file to be checked
            @return True if it does and false if it does not
        */
		bool FileExists (const std::string &filename);

        /**
            @brief Asks the size of the file
            @param[in] filename Reference to the path of the file to be checked
            @return The size of the file
        */
		long GetFileSize (const std::string &filename);

        /**
            @brief Gets the real target path and opens a zipped folder if needed
            @param[in] filename Reference to the abstract path of the file
            @return The path to the real file with 'extras' (ZIPPER)
        */
		PATH_DIR GetTargetPath (const std::string &filename);
};

/**
    @brief Checks if the file exists (no fancy stuff - use the FILEHANDLER for more features)
    @param[in] filename Reference to the path of the file to be checked
    @return True if it does and false if it does not
*/
bool FileExists (const std::string &filename);

/** The main filehandler singleton */
extern FILEHANDLER MainFileHandler;

};

#endif //G3_FILE_HANDLER_H

